#pragma once
#include <iostream>
#include <string>
#include <strings.h>
#include <cstdlib>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "protocol.hpp"
#define NUM 1024
class TcpClient
{
public:
    TcpClient(const std::string &ip, const uint16_t &port)
        : _serverip(ip), _serverport(port), _sockfd(-1)
    {
    }
    void initClient()
    {
        // 创建套接字对象
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd == -1)
        {
            std::cerr << "socket error" << std::endl;
            exit(2);
        }
        std::cout << "socket success" << std::endl;

        // 不需要手动绑定ip和端口
    }
    void start()
    {
        // 与服务器建立连接
        struct sockaddr_in server;
        bzero(&server, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = inet_addr(_serverip.c_str());
        server.sin_port = htons(_serverport);
        int n = connect(_sockfd, (struct sockaddr *)&server, sizeof(server));
        if (n == -1)
        {
            std::cerr << "connect error" << std::endl;
            exit(3);
        }
        std::cout << "connect server success" << std::endl;
        std::string message;
        std::string inbuffer;
        while (1)
        {
            //1.输入请求
            std::cout << "cin>>> ";
            std::getline(std::cin, message);
            //2.解析请求
            Request req;
            if(!parseMessage(message, &req)) break;

            //3.序列化请求
            std::string req_str;
            req.serialize(&req_str);

            //4.添加报头
            std::string req_package;
            enLenth(req_str, req_package);

            //5.发送请求
            send(_sockfd, req_package.c_str(), req_package.size(), 0);

            //6.获取响应报文
            std::string resp_package;
            if(!recvPackage(_sockfd, inbuffer, &resp_package)) break;

            //7.去掉报头
            std::string resp_str;
            deLenth(resp_package, resp_str);

            //8.对响应反序列化
            Response resp;
            resp.deserialize(resp_str);
            
            std::cout << "exitcode: " << resp.exitcode << "\nresult: " << resp.result << std::endl;
        }
    }

    // "12*21"
    bool parseMessage(const std::string &message, Request *req)
    {
        std::string left;
        std::string right;
        char op;
        int i = 0;
        int sz = message.size();
        int status = 0; // 0表示运算符左边  1表示运算符 2表示运算符右边
        while (i < sz)
        {
            switch (status)
            {
            case 0:
            {
                if (isdigit(message[i]))
                {
                    left += message[i++];
                }
                else
                {
                    status = 1;
                }
            }
            break;
            case 1:
            {
                op = message[i++];
                status = 2;
            }
            break;
            case 2:
                right += message[i++];
            }
        }
        req->x = std::stoi(left);
        req->y = std::stoi(right);
        req->op = op;
        return true;
    }
    ~TcpClient()
    {
        if (_sockfd >= 0)
            close(_sockfd);
    }

private:
    std::string _serverip;
    uint16_t _serverport;
    int _sockfd;
};
